package ar.edu.valetinis.modulo1.controlador;

import java.util.Date;
import java.util.List;

import ar.edu.valetinis.modulo1.modelo.OrdenDeCompra;
import ar.edu.valetinis.modulo1.modelo.OrdenDeCompraCerradaState;
import ar.edu.valetinis.modulo1.modelo.OrdenDeCompraDetalle;
import ar.edu.valetinis.modulo1.modelo.OrdenDeCompraEmitidaState;
import ar.edu.valetinis.modulo1.modelo.OrdenDeCompraProveedorState;
import ar.edu.valetinis.modulo1.modelo.Pedido;
import ar.edu.valetinis.modulo1.modelo.PedidoDetalle;
import ar.edu.valetinis.modulo1.modelo.Producto;
import ar.edu.valetinis.modulo1.modelo.Proveedor;
import ar.edu.valetinis.modulo1.modelo.Recepcion;

/**
 * @author Nestor Valentinis
 * 
 * */
public class PedidoControler {

	private List<Producto> productosItems;
	private List<Pedido> pedidosItems;
	private static PedidoControler instance = new PedidoControler(); //lo carga el classLoader
	
	//constructor privado para anular el constructor por defecto
	private PedidoControler() {		
	}

	//actions
	
	public static PedidoControler getInstance() {
		return instance;
	}
	
	/**
	 * Metodo que contorla el stock de los productos y genera los pedidos 
	 * si el stock llego al minimo.
	 * */	
	public void controlarStock() {
		
		for(Producto item : this.productosItems) {
			
			if( !item.checkSotck() ) {
				
				this.pedidosItems.add( this.generarPedido(item) );
			}
		}
	}
	
	/**
	 * Metodo que genera el pedido o agrega el producto 
	 * a un detalle de pedido ya creado
	 * */
	public Pedido generarPedido(Producto p) {
		
		PedidoDetalle pedidoDetalle = new PedidoDetalle();
		pedidoDetalle.setCantidad(p.getCantidadAReponer());
		pedidoDetalle.setProducto(p);
		
		Pedido pedidoAux = getPedidoVigente( p.getProveedor() );
				
		pedidoAux.setFechaCreacion( new Date() );		
		pedidoAux.setProveedor( p.getProveedor() );
		pedidoAux.addItemToDetalle( pedidoDetalle );
		
		return pedidoAux;
	}
	
	/**
	 * Metodo que verifica si existe un pedido vigente para ese proveedor 
	 * si no retorna un nuevo Pedido
	 * */
	public Pedido getPedidoVigente(Proveedor p) {		
		
		for( Pedido itemPedido : this.pedidosItems ) {
			
			if( itemPedido.getProveedor().equals(p) 
					&& itemPedido.getOrden().getEstadoActual() instanceof OrdenDeCompraEmitidaState ) {
				
				return itemPedido;
			}
		}
		
		Pedido newPedido = new Pedido();
		newPedido.setOrden( this.generarOrdenDeCompra(newPedido) );
		
		return newPedido;		
	}
	
	/**
	 * Metodo que ejecuta el proveedor para confiramr el pedido
	 * */
	public Boolean confirmarPedido(Pedido pedido, Date fechaConfirmacionPedido, 
			Date fechaEstimadaEntrega) {
		
		for( Pedido itemPedido : this.pedidosItems ) {
			
			if( itemPedido.equals(pedido) ) {
				
				itemPedido.setFechaConfirmacionPedido(fechaConfirmacionPedido);
				itemPedido.setFechaEstimadaEntrega(fechaEstimadaEntrega);
				itemPedido.getOrden().setEstadoActual( new OrdenDeCompraProveedorState() );
				
				return Boolean.TRUE;
			}			
		}
		
		return Boolean.FALSE;
	}
	
	/**
	 * Metodo que se ejecuta para mandar un mail al proveedor
	 * */
	public void enviarMailDeConfirmacion( Pedido pedido ) {
		
		//FIXME logiga que envia un mail al proveedor confirmando el pedido
	}
	
	/**
	 * Metodo que genera la orden de compra en base a un Pedido
	 * */
	public OrdenDeCompra generarOrdenDeCompra( Pedido pedido ) {
		
		OrdenDeCompra orden = new OrdenDeCompra();
		
		for( PedidoDetalle itemPedido : pedido.getPedidoDetalle() ) {
			
			OrdenDeCompraDetalle ordenDetalle = new OrdenDeCompraDetalle();
			ordenDetalle.setCantidadPedida( itemPedido.getCantidad() );
			ordenDetalle.setProducto( itemPedido.getProducto() );			
			orden.addItemToDetalle(ordenDetalle);
		}
		
		orden.setNroOrden(00000L); //FIXME asignar un nro de orden
		orden.setFechaCreacion( new Date() );
		orden.setPedido(pedido);
		orden.setEstadoActual( new OrdenDeCompraEmitidaState() );
		
		//se envia el mail al proveedor del producto
		this.enviarMailDeConfirmacion(pedido);
		
		return orden;
	}
	
	/**
	 * Recibe un pedido con una OrdenDeCompra con catidades
	 * actualizadas, controla q las cantidades correctas
	 * */
	public void recibirPedido( Pedido pedido ) {
		
		//TODO logica de la recepcion de pedido		
		
	}
	
	public void actualizarStock() {
		
		//TODO logica de la actualizaciond e stock
	}
	
	//getter & setter
		
	public void setProductosItems(List<Producto> productosItems) {
		this.productosItems = productosItems;
	}

	public List<Producto> getProductosItems() {
		return productosItems;
	}
	
}
